iT邦幫忙

2025 iThome 鐵人賽

DAY 1
0

https://ithelp.ithome.com.tw/upload/images/20250831/20118113BLkCodRJyL.png

緣起

在學習網頁開發前端的框架React和Vue的過程中,常常遇到函數式程式設計(Functional Programming)相關的術語,例如Pure function, Immutable, Side Effect…等名詞,於是很好奇的去搜了一些以Javascript實現Functional Programming相關的文章、影片和書籍,結果卻發現踩了一個大坑,難以自拔。

往後的內容會以FP縮寫代表函數式程式設計(Functional Programming)

由於Javascript並不是為FP設計的語言,所以學習之路有些坎坷。一些Javascript函式庫如Ramda、Lodash/fp的說明文件比較以個別函式功能性說明,而且函式的型別簽名(Signature)都是以Hindley-Milner的格式出現,Youtube上也很少有完整函式程式設計概念的說明,而且一些從未見過的奇怪名詞Functor, Monade, ...出現,讓我這個應用數學系畢業的數學老師頗為汗顏和緊張,一些ITHome的文章也是形容的很神奇,最終是在一本mostly-adequate-guide-to-functional-programming的書上對Option、Either、IO和Task這些內容有了初步的了解。

後來跟隨潮流學習了Typescript,於是便接觸了fp-ts這個typescript的FP函式庫,這個函式庫是基於仿造Haskell和Scala這種FP的程式語言所開發,但並沒有每一個函式庫完整的使用說明,雖然將所有列出的學習資源都看得差不多後,還是覺得有些不足之處,終於在百般不奈之下,只好去學了Haskell這個語言,總算有些豁然開朗的感覺,於是利用鐵人賽的機會,將自己學習fp-ts和函數式程式設計的心得和鐵友們分享。

因為前端的網頁開發必須在javascript的環境下開發,因此fp-ts設計的目標是希望在typescript架構下,打造一個接近Haskell或Scala的FP語言環境。然而,typescript雖然有了型別的能力,但並不是完全為FP設計的程式語言,如果您是已經熟悉Typescript或Javascript的開發者,可以自行切換程式設計方式,不必拘泥;但是此系列文章會儘量遵從純FP語言的規範來介紹,將Typescript和fp-ts視為一語言體系,並且以一種全新語言的概念來介紹,希望完全沒有Typescript和Javascript基礎的人也能重頭學習。

架構

本系列文章會介紹

  1. FP的觀念
  2. Typescript
  3. fp-ts

以下是這次30天規劃的內容,但是「計畫總是趕不上變化」,如果有新的靈感會隨時進行內容的更動與調整。

Day 01 緣起

Day 02 「型別」請「集合」 - Type is Set

Day 03 一切都是函數 - Function

Day 04 型別也可以是變數 - 泛型

Day 05 模組化設計 - 匯出(export) & 匯入(import)

Day 06 遞迴函數 - Recurrsion

Day 07 宣告式程式風格 - Javascript Array

Day 08 今天來一些咖哩 - Currying

Day 09 讓函數「接管」程式設計 - 函數的合成

Day 10 FP程式設計範例 - 淺嚐密碼學(Cipher)

Day 11 fp-ts簡介與Array

Day 12 錯誤處理 - Option & Either

Day 13 隔空取物 - Applicative Functor

Day 14 化同存異 - Monad Functior

Day 15 輸出入處理 - IO & Do notation

Day 16 非同步工作 - Task & TaskEither

Day 17 除錯 - trace & tap

Day 18 自然轉換 - Natural Transformation

Day 19 函數型別容器 - Reader & State

Day 20 fp-ts綜合練習

Day 21 Contravariant Functor - Eq & Ord

Day 22 ADT-Algebraic Data Type

Day 23 時空穿越 - Traverse & Sequence

Day 24 型別的型別 - Higher Kinded Types(HKT)

Day 24 打造自己的Monad

Day 26 Tree

Day 27 Zipper

Day 28 Zipper 的應用

Day 29 FP實作範例

Day 30 曲終人不散

抽象化思考

抽象化思考是數學最大的武器,小學的時候,「2瓶牛奶4公升,求1瓶牛奶多少公升?」,多數人都知道4 ÷ 2 = 2,改問「2/3瓶牛奶4公升,求1瓶牛奶多少公升?」,能力好的學生,便會依樣畫葫蘆,4 ÷ (2/3) = 4,這便是抽象化的開始。在學習一元二次方程式ax²+bx+c=0時,我們並不知道x是分數、實數還是複數,因為他們享有共通的代數規則,所以我們可以用配方法來得到公式解。特別提抽象化這個能力是因為在學習函數式程式設計第二階段便是一種抽象化的過程,我們不必需要對很多函數和模組的實作有足夠的了解,或者說根不用去了解實作,只要了解共同的規則即可。如此,我們只要學習一個模組,便很快可以應用到其它模組。

擔任數學教師的過程,很多學生常要問「學數學做什麼?」,這是很多數學老師的非常難的問題,因為一般人生活上很少用到我們從國中之後學習到的數學,即便很多人念了大學,許多學工程的人,學習了微積分、線性代數,也不知道為什麼要學這些數學。我常這樣比喻,學數學在工程或科學的範疇裏,就像是人類在開飛機。工程和科學有兩大途徑向前進步,一個是實作或實驗,另一個是用理論推導。實作或實驗就像是陸地上行走,走的速度慢,一步一步前進;開飛機在天上飛,終究是速度快很多。但是我也遇到很多人,只會在天上開飛機,卻不會起飛和落地,因此無法真正體會數學的應用。一切終究是要接地氣,才能是一趟完整的旅程,數學也是如此,而且起飛和落地是最困難的一部分。

開發環境

個人在Node.js使用typescript進行開發,Node.js可逕行到官網下載,node下載時會順便安裝npm這個node套件管理程式(node package manager)。建立專案目錄後並進入專案目錄後,便依以下的簡略說明設定整個專安的步驟和指令。

1. 起始化專案

指令: npm -init -y
說明: 建立package.json檔。

2. 安裝typescript、@types/node、rimraf

指令: npm i -D @types/node typescript rimraf
說明: 我們安裝了 rimraf 作為開發依賴,用來在不同平台上統一刪除檔案或資料夾。

3. 初始化typescript

指令: npx tsc --init
說明: 建立tsconfig.json檔。

4. 配置typescript

// @tsconfig.json
{
  "compilerOptions": {
    // 其它省略
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"],
  "exclude": ["src/**/*.spec.ts"]
}

說明: 修改tsconfig.json檔,經由tsc(typescript編譯器)編譯過而得的js程式碼的目錄會放在專案目錄下的dist目錄,而src下的ts檔案都會被編譯成一個main.js檔。

4. 配置package.json

// @package.json
{
// 其餘省略
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rimraf dist && tsc",
    "build:dev": "rimraf dist && tsc --watch",
    "start": "rimraf dist && tsc && node dist/main.js",
    "start:dev": "rimraf dist && node dist/main.js"
  },
// 其餘省略

}

說明:

  1. build指令會移除dist目錄內的檔案並且將src內的檔案編譯,build:dev指令讓tsc在監看模式下執行,當檔案有變動且存檔時會自動進行編譯。
  2. start指令除了編譯ts檔之外,也會執行main.js檔,start:dev則直接執行main.js檔(因為已經在監看模式下)。
  3. 如果要執行build指令,只需在terminal輸入npm run build指令執行即可,其它scripts下的指令皆可如此執行。

4. 開始上路

在src下建立main.ts即可開始我們的鐵人專案。

我在stackblitz準備了一個起始專案,如果不想自己從頭在自己的電腦從頭開始,可以Fork stackblitz下的專案並且在stackblitz的環境執行,輕鬆又方便。專案的連結位置(https://stackblitz.com/edit/stackblitz-starters-xsvhdqzn?file=package.json)

今日小結

闊別了鐵人賽兩年,這次的鐵人寫作主要的目的是能完成一個以fp-ts基礎的函數式程式設計的學習心得,希望能幫助以typescript為開發語言而想學習函數式程式設計的朋友,由於學習時間尚短,開發經驗不足,許多疏漏和錯誤之處,也歡迎大家指正和討論,就讓我們開始這次的鐵人之旅!


下一篇
Day02. 「型別」請「集合」 - Type is Set
系列文
數學老師學函數式程式設計 - 以fp-ts啟航22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言